// 10.4 再探迭代器
/**
 * 除了为每个容器定义的迭代器之外，标准库在头文件iterator中还定义了额外几种迭代器。
 * 1. 插入迭代器：被绑定到一个容器上，用来向容器插入元素。
 * 2. 流迭代器：被绑定到输入或输出流上，用来遍历所关联的IO流。
 * 3. 反向迭代器：向后而不是向前移动，除了forward_list之外的标准库容器都有反向迭代器。
 * 4. 移动迭代器：这些专用的迭代器不拷贝其中的元素，而是移动它们。
 */

#include <iterator>
#include <vector>
#include <list>
#include <deque>
#include <forward_list>
#include <string>
#include <array>
#include <stack>
#include <queue>
#include <algorithm>
#include <numeric>
#include <functional>
#include <iostream>
using std::swap;
using std::vector, std::list, std::deque, std::forward_list, std::string, std::array, std::stack, std::queue;
#include "../Chapter07/Sales_data.h"
#include "../Chapter01/Sales_item.h"
using std::begin, std::cbegin, std::end, std::cend, std::find, std::accumulate, std::equal, std::fill, std::fill_n, std::back_inserter;
using std::cin, std::cout, std::endl;
using std::copy, std::replace, std::replace_copy, std::sort, std::unique, std::stable_sort, std::find_if, std::for_each;
using std::ostream, std::ref;
using std::transform, std::bind, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3;
using namespace std;

int main()
{
    // 10.4.2 iostream迭代器
    // 虽然iostream类型不是容器，但标准库定义了可以用于这些IO类型对象的迭代器（参见8.1节，第278页）。
    // istream_iterator（参见表10.3）读取输入流，ostream_iterator（参见表10.4节，第361页）向一个输出流写数据。

    // istream_iterator操作
    istream_iterator<int> int_iter(cin); // 从cin读取int
    istream_iterator<int> int_eof;       // 尾后迭代器
    vector<int> vec;
    while (int_iter != int_eof)
    {
        // 后置递增运算读取流，返回迭代器的旧值
        // 解引用迭代器，获得从流读取的前一个值
        vec.push_back(*int_iter++);
        // 后置递增运算会从流中读取下一个值，向前推进，但返回的是迭代器的旧值。
        // 迭代器的旧值包含了从流中读取的前一个值，对迭代器进行解引用就能获得此值。
    }
    istream_iterator<int> in_iter(cin); // 从cin读取int
    istream_iterator<int> in_eof;       // 尾后迭代器
    vector<int> vec1(in_iter, in_eof);  // 等价于上面的while循环，这里是用一对表示元素范围的流迭代器来构造vec1.

    // 使用算法操作流迭代器
    istream_iterator<int> in(cin), eof;
    cout << accumulate(in, eof, 0) << endl; // 输出控制台所有合法的输入的值的累加和

    // istream_iterator允许使用懒惰求值
    // 当我们将一个istream_iterator绑定到一个流时，标准库并不保证迭代器立即从流读取数据。
    // 具体实现可以推迟从流中读取数据，直到我们使用迭代器时才真正读取。

    // ostream_iterator操作
    // 使用ostream_iterator输出值的序列：
    ostream_iterator<int> out_iter(cout, " ");
    for (auto e : vec)
    {
        *out_iter++ = e; // 赋值语句实际上将元素写到cout
        // out_iter = e; // 同上，第二种形式
    }
    cout << endl;
    // 运算符*和++实际上对ostream_iterator对象不做任何事情，因此忽略它们对我们的程序没有任何影响。但是，推荐第一种形式。
    // 也可以调用copy来打印vec中的元素，这样比循环更简单
    copy(vec.begin(), vec.end(), out_iter);
    cout << endl;

    // 使用流迭代器处理类类型
    // 由于Sales_item既有输入运算符也有输出运算符，因此可以使用IO迭代器重写1.6节（第21页）中的书店程序：[插图]
    istream_iterator<Sales_item> item_iter(cin), item_eof;
    ostream_iterator<Sales_item> itemout_iter(cout, "\n");
    Sales_item sum = *item_iter++; // 将第一笔交易记录存在sum中，并读取下一条记录
    while (item_iter != item_eof)
    {
        if (item_iter->isbn() == sum.isbn()) // 如果当前记录与sum中的isbn号一致
        {
            sum += *item_iter++; // 将其加到sum上并读取下一条记录
        }
        else
        {
            itemout_iter = sum; // 输出sum当前值
            sum = *item_iter++; // 读取下一条记录
        }
    }
    itemout_iter = sum; // 记得打印组后一组记录的和

    return 0;
}
